package system.back;

import java.util.*;

import system.struct.AggEntry;
import system.struct.LogEntry;
import system.struct.ParserResult;
import system.struct.SearchEntry;
import system.util.Util;

/**
 * Fetcher of system
 * 
 * <p>
 * Used to fetch information from the loaded information (<tt>Loader</tt> info)
 * according to given <tt>ParserResult</tt> and return a <tt>List</tt> of
 * <tt>SearchEntry</tt> for later processing
 * 
 * @author Jack
 * 
 */
public class Fetcher {

	/** Loaded information */
	Loader info;

	/**
	 * Constructs a <tt>Fetcher</tt> using a <tt>Loader</tt>
	 * 
	 * @param info
	 *            a <tt>Loader</tt> used to hold information
	 */
	public Fetcher(Loader info) {
		this.info = info;
	}

	/**
	 * Returns fetched result list according to <tt>ParserResult</tt>
	 * 
	 * @param pr
	 *            <tt>ParserResult</tt> that contains information from
	 *            <tt>Parser</tt>
	 * @return a list of <tt>SearchEntry</tt>
	 */
	public ArrayList<SearchEntry> fetchLog(ParserResult pr) {
		String[] cnptList = pr.getCnptList();
		if (cnptList.length == 0)
			return new ArrayList<SearchEntry>();
		ArrayList<ArrayList<SearchEntry>> resList = new ArrayList<ArrayList<SearchEntry>>();
		for (int i = 0; i < cnptList.length; i++) {
			// fetch all concepts' aggregation list
			resList.add(agg2Search(info.getAggList(info
					.indexOfCnpt(cnptList[i]))));
		}
		ArrayList<SearchEntry> ar1, ar2;
		while (resList.size() != 1) {
			ar1 = resList.remove(resList.size() - 1);
			ar2 = resList.remove(resList.size() - 1);
			resList.add(intercept(ar1, ar2));
		}
		return resList.get(0);
	}

	/**
	 * Returns the <i>Intercept</i> of two <tt>SearchEntry</tt> List
	 * 
	 * @param ar1
	 *            <i>List1</i>
	 * @param ar2
	 *            <i>list2</i>
	 * @return <i>Intercept List</i>
	 */
	private ArrayList<SearchEntry> intercept(ArrayList<SearchEntry> ar1,
			ArrayList<SearchEntry> ar2) {
		ArrayList<SearchEntry> ans = new ArrayList<SearchEntry>();
		if (ar1.size() == 0 || ar2.size() == 0)
			return ans;
		HashMap<Integer, SearchEntry> map = new HashMap<Integer, SearchEntry>();
		for (int i = 0; i < ar1.size(); i++) {
			map.put(ar1.get(i).qIndex(), ar1.get(i));
		}
		int qIndex;
		SearchEntry se1, se2;
		for (int i = 0; i < ar2.size(); i++) {
			se2 = ar2.get(i);
			qIndex = se2.qIndex();
			se1 = map.get(qIndex);
			if (se1 != null) {
				se2.cutKeywords(info.getInst(se1.iIndex()));
				ans.add(se2);
			}
		}
		return ans;
	}

	/**
	 * Returns <tt>List</tt> of <tt>SearchEntry</tt> according to given
	 * <tt>List</tt> of <tt>AggEntry</tt>
	 * 
	 * @param aggList
	 *            <tt>List</tt> of <tt>AggEntry</tt>
	 * @return <tt>List</tt> of <tt>SearchEntry</tt>
	 */
	private ArrayList<SearchEntry> agg2Search(ArrayList<AggEntry> aggList) {
		ArrayList<SearchEntry> ans = new ArrayList<SearchEntry>();
		if (aggList == null || aggList.size() == 0)
			return ans;
		int end = aggList.size();
		for (int i = 0; i < end; i++) {
			AggEntry ae = aggList.get(i);
			LogEntry le = info.getLogEntry(ae.qIndex());
			String keywords = le.getQuery();
			keywords = Util.replaceAll(keywords, info.getInst(ae.iIndex()));
			ans.add(new SearchEntry(le, keywords, ae.iIndex()));
		}
		return ans;
	}

}
